home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
201-225
/
223
/
iff2sun
/
convert.c
next >
Wrap
C/C++ Source or Header
|
1995-03-13
|
21KB
|
852 lines
/*
* Apply median cut on an image.
*
* median [-c n] [-f] input output
* -c n - set colortable size. Default is 256.
* -f - use Floyd-Steinberg dithering.
* -lzw - compress output with LZW
* -none - use no compression on output
* -picio - use picio compression on output
* -packbits - use packbits compression on output
* -rowsperstrip n - create output with n rows/strip of data
* (by default the compression scheme and rows/strip are taken
* from the input file)
*
* Notes:
*
* [1] Floyd-Steinberg dither:
* I should point out that the actual fractions we used were, assuming
* you are at X, moving left to right:
*
* X 7/16
* 3/16 5/16 1/16
*
* Note that the error goes to four neighbors, not three. I think this
* will probably do better (at least for black and white) than the
* 3/8-3/8-1/4 distribution, at the cost of greater processing. I have
* seen the 3/8-3/8-1/4 distribution described as "our" algorithm before,
* but I have no idea who the credit really belongs to.
* Also, I should add that if you do zig-zag scanning (see my immediately
* previous message), it is sufficient (but not quite as good) to send
* half the error one pixel ahead (e.g. to the right on lines you scan
* left to right), and half one pixel straight down. Again, this is for
* black and white; I've not tried it with color.
* --
* Lou Steinberg
*
* [2] Color Image Quantization for Frame Buffer Display, Paul Heckbert,
* Siggraph '82 proceedings, pp. 297-307
*/
#include <stdio.h>
#include <sys/types.h>
#include <rasterfile.h>
#define MAX_CMAP_SIZE 256
#define howmany(x, y) (((x)+((y)-1))/(y))
#define streq(a,b) (strcmp(a,b) == 0)
#define COLOR_DEPTH 8
#define MAX_COLOR 256
#define B_DEPTH 4 /* # bits/pixel to use */
#define B_LEN (1<<B_DEPTH)
#define C_DEPTH 2
#define C_LEN (1<<C_DEPTH) /* # cells/color to use */
#define COLOR_SHIFT (COLOR_DEPTH-B_DEPTH)
#define COMPRESSION_NONE 0
#define COMPRESSION_PACKBITS 1
#define COMPRESSION_LZW 2
#define COMPRESSION_PICIO 3
typedef struct colorbox {
struct colorbox *next, *prev;
int rmin, rmax;
int gmin, gmax;
int bmin, bmax;
int total;
} Colorbox;
typedef struct {
int num_ents;
int entries[MAX_CMAP_SIZE][2];
} C_cell;
u_short rm[MAX_CMAP_SIZE], gm[MAX_CMAP_SIZE], bm[MAX_CMAP_SIZE];
int bytes_per_pixel;
long num_colors, width, hieght, length;
int histogram[B_LEN][B_LEN][B_LEN];
Colorbox *freeboxes;
Colorbox *usedboxes;
Colorbox *largest_box();
C_cell **ColorCells;
FILE *in, *out;
char *usage = "usage: median [-c n] [-f] [-none] [-lzw] [-picio] [-packbits] [-rowsperstrip r] input output\n";
main(argc, argv)
int argc;
char **argv;
{
struct rasterfile header;
int i, j, dither = 0;
long chunk;
char *ifile_name = NULL, *ofile_name = NULL, color;
Colorbox *box_list, *ptr;
u_short rowsperstrip = 128, compression = -1, shortv;
u_short bitspersample, samplesperpixel, photometric;
float floatv;
num_colors = MAX_CMAP_SIZE;
for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
if (streq(argv[0], "-f")) {
dither = 1;
continue;
}
if (streq(argv[0], "-c")) {
argc--, argv++;
if (argc < 1) {
fprintf(stderr, "-c: missing colormap size\n%s",
usage);
exit(1);
}
num_colors = atoi(argv[0]);
if (num_colors > MAX_CMAP_SIZE) {
fprintf(stderr,
"-c: colormap too big, max %d\n%s",
MAX_CMAP_SIZE, usage);
exit(1);
}
continue;
}
if (streq(argv[0], "-none")) {
compression = COMPRESSION_NONE;
continue;
}
if (streq(argv[0], "-packbits")) {
compression = COMPRESSION_PACKBITS;
continue;
}
if (streq(argv[0], "-lzw")) {
compression = COMPRESSION_LZW;
continue;
}
if (streq(argv[0], "-picio")) {
compression = COMPRESSION_PICIO;
continue;
}
if (streq(argv[0], "-rowsperstrip")) {
argc--, argv++;
rowsperstrip = atoi(argv[0]);
continue;
}
fprintf(stderr, "%s: unknown option\n%s", argv[0], usage);
exit(1);
}
if (argc < 2) {
fprintf(stderr, "%s", usage);
exit(-1);
}
in = fopen(argv[0], "r");
if (in == NULL)
exit(-1);
fread(&width, 4, 1, in); /* Get size of picture */
fread(&hieght, 4, 1, in);
length = hieght;
/*
* STEP 1: create empty boxes
*/
usedboxes = NULL;
box_list = freeboxes = (Colorbox *)malloc(num_colors*sizeof (Colorbox));
freeboxes[0].next = &freeboxes[1];
freeboxes[0].prev = NULL;
for (i = 1; i < num_colors-1; ++i) {
freeboxes[i].next = &freeboxes[i+1];
freeboxes[i].prev = &freeboxes[i-1];
}
freeboxes[num_colors-1].next = NULL;
freeboxes[num_colors-1].prev = &freeboxes[num_colors-2];
/*
* STEP 2: get histogram, initialize first box
*/
ptr = freeboxes;
freeboxes = ptr->next;
if (freeboxes)
freeboxes->prev = NULL;
ptr->next = usedboxes;
usedboxes = ptr;
if (ptr->next)
ptr->next->prev = ptr;
get_histogram(in, ptr);
/*
* STEP 3: continually subdivide boxes until no more free
* boxes remain or until all colors assigned.
*/
while (freeboxes != NULL) {
ptr = largest_box();
if (ptr != NULL)
splitbox(ptr);
else
freeboxes = NULL;
}
/*
* STEP 4: assign colors to all boxes
*/
for (i = 0, ptr = usedboxes; ptr != NULL; ++i, ptr = ptr->next) {
rm[i] = ((ptr->rmin + ptr->rmax) << COLOR_SHIFT) / 2;
gm[i] = ((ptr->gmin + ptr->gmax) << COLOR_SHIFT) / 2;
bm[i] = ((ptr->bmin + ptr->bmax) << COLOR_SHIFT) / 2;
}
fprintf(stderr,"Number of colors used %d\n", i);
/* We're done with the boxes now */
free(box_list);
box_list = freeboxes = usedboxes = NULL;
/*
* STEP 5: scan histogram and map all values to closest color
*/
/* 5a: create cell list as described in Heckbert[2] */
ColorCells = (C_cell **)calloc(C_LEN*C_LEN*C_LEN, sizeof (C_cell *));
/* 5b: create mapping from truncated pixel space to color
table entries */
map_colortable();
/*
* STEP 6: scan image, match input values to table entries
*/
out = fopen(argv[1], "w");
if (out == NULL)
exit(-2);
header.ras_magic= 0x59a66a95;
header.ras_width= width;
header.ras_height= hieght;
header.ras_depth= 8;
header.ras_length= width * hieght;
header.ras_type= RT_STANDARD;
header.ras_maptype= RMT_EQUAL_RGB;
header.ras_maplength= 3*256;
/* Write out the rasterfile header to the ouput */
fwrite(&header, sizeof(header), 1, out);
/* Write the colormap to the ouput */
for(i=0;i<256;i++) {
color = (char)rm[i];
fwrite(&color, 1, 1, out);
}
for(i=0;i<256;i++) {
color = (char)gm[i];
fwrite(&color, 1, 1, out);
}
for(i=0;i<256;i++) {
color = (char)bm[i];
fwrite(&color, 1, 1, out);
}
rewind(in); /* rewind input file XXX */
fread(&chunk, 4, 1, in);
fread(&chunk, 4, 1, in);
if (dither)
quant_fsdither(in, out);
else
quant(in, out);
(void) fclose(out);
}
static
get_histogram(in, box)
FILE *in;
register Colorbox *box;
{
register u_char *inptr;
register int red, green, blue, j, i;
u_char *inline;
i = 24 * width;
inline = (u_char *)malloc(howmany(i, 8));
if (inline == NULL) {
fprintf(stderr, "No space for scanline buffer\n");
exit(-1);
}
box->rmin = box->gmin = box->bmin = 999;
box->rmax = box->gmax = box->bmax = -1;
box->total = width * length;
{ register int *ptr = &histogram[0][0][0];
for (i = B_LEN*B_LEN*B_LEN; --i >= 0;)
*ptr++ = 0;
}
for (i = length; i-- > 0;) {
if (fread(inline, width*3, 1, in) <= 0)
break;
inptr = inline;
for (j = width; j-- > 0;) {
red = *inptr++ >> COLOR_SHIFT;
green = *inptr++ >> COLOR_SHIFT;
blue = *inptr++ >> COLOR_SHIFT;
if (red < box->rmin)
box->rmin = red;
if (red > box->rmax)
box->rmax = red;
if (green < box->gmin)
box->gmin = green;
if (green > box->gmax)
box->gmax = green;
if (blue < box->bmin)
box->bmin = blue;
if (blue > box->bmax)
box->bmax = blue;
histogram[red][green][blue]++;
}
}
free(inline);
}
static Colorbox *
largest_box()
{
register Colorbox *p, *b;
register int size;
b = NULL;
size = -1;
for (p = usedboxes; p != NULL; p = p->next)
if ((p->rmax > p->rmin || p->gmax > p->gmin ||
p->bmax > p->bmin) && p->total > size)
size = (b = p)->total;
return (b);
}
static
splitbox(ptr)
register Colorbox *ptr;
{
int hist2[B_LEN];
int first, last;
register Colorbox *new;
register int *iptr, *histp;
register int i, j;
register int ir,ig,ib;
register int sum, sum1, sum2;
int total;
enum { RED, GREEN, BLUE } axis;
/*
* See which axis is the largest, do a histogram along that
* axis. Split at median point. Contract both new boxes to
* fit points and return
*/
i = ptr->rmax - ptr->rmin;
if (i >= ptr->gmax - ptr->gmin && i >= ptr->bmax - ptr->bmin)
axis = RED;
else if (ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin)
axis = GREEN;
else
axis = BLUE;
/* get histogram along longest axis */
switch (axis) {
case RED:
histp = &hist2[ptr->rmin];
for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
*histp = 0;
for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
iptr = &histogram[ir][ig][ptr->bmin];
for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
*histp += *iptr++;
}
histp++;
}
first = ptr->rmin;
last = ptr->rmax;
break;
case GREEN:
histp = &hist2[ptr->gmin];
for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
*histp = 0;
for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
iptr = &histogram[ir][ig][ptr->bmin];
for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
*histp += *iptr++;
}
histp++;
}
first = ptr->gmin;
last = ptr->gmax;
break;
case BLUE:
histp = &hist2[ptr->bmin];
for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
*histp = 0;
for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
iptr = &histogram[ir][ptr->gmin][ib];
for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
*histp += *iptr;
iptr += B_LEN;
}
}
histp++;
}
first = ptr->bmin;
last = ptr->bmax;
break;
}
/* find median point */
histp = &hist2[first];
sum2 = ptr->total / 2;
histp = &hist2[first];
sum = 0;
for (i = first; i <= last && (sum += *histp++) < sum2; ++i)
;
if (i == first)
i++;
/* Create new box, re-allocate points */
new = freeboxes;
freeboxes = new->next;
if (freeboxes)
freeboxes->prev = NULL;
if (usedboxes)
usedboxes->prev = new;
new->next = usedboxes;
usedboxes = new;
total = ptr->total;
histp = &hist2[first];
for (sum1 = 0, j = first; j < i; j++)
sum1 += *histp++;
for (sum2 = 0, j = i; j <= last; j++)
sum2 += *histp++;
new->total = sum1;
ptr->total = sum2;
new->rmin = ptr->rmin;
new->rmax = ptr->rmax;
new->gmin = ptr->gmin;
new->gmax = ptr->gmax;
new->bmin = ptr->bmin;
new->bmax = ptr->bmax;
switch (axis) {
case RED:
new->rmax = i-1;
ptr->rmin = i;
break;
case GREEN:
new->gmax = i-1;
ptr->gmin = i;
break;
case BLUE:
new->bmax = i-1;
ptr->bmin = i;
break;
}
shrinkbox(new);
shrinkbox(ptr);
}
static
shrinkbox(box)
register Colorbox *box;
{
register int *histp, ir, ig, ib;
if (box->rmax > box->rmin) {
for (ir = box->rmin; ir <= box->rmax; ++ir)
for (ig = box->gmin; ig <= box->gmax; ++ig) {
histp = &histogram[ir][ig][box->bmin];
for (ib = box->bmin; ib <= box->bmax; ++ib)
if (*histp++ != 0) {
box->rmin = ir;
goto have_rmin;
}
}
have_rmin:
if (box->rmax > box->rmin)
for (ir = box->rmax; ir >= box->rmin; --ir)
for (ig = box->gmin; ig <= box->gmax; ++ig) {
histp = &histogram[ir][ig][box->bmin];
ib = box->bmin;
for (; ib <= box->bmax; ++ib)
if (*histp++ != 0) {
box->rmax = ir;
goto have_rmax;
}
}
}
have_rmax:
if (box->gmax > box->gmin) {
for (ig = box->gmin; ig <= box->gmax; ++ig)
for (ir = box->rmin; ir <= box->rmax; ++ir) {
histp = &histogram[ir][ig][box->bmin];
for (ib = box->bmin; ib <= box->bmax; ++ib)
if (*histp++ != 0) {
box->gmin = ig;
goto have_gmin;
}
}
have_gmin:
if (box->gmax > box->gmin)
for (ig = box->gmax; ig >= box->gmin; --ig)
for (ir = box->rmin; ir <= box->rmax; ++ir) {
histp = &histogram[ir][ig][box->bmin];
ib = box->bmin;
for (; ib <= box->bmax; ++ib)
if (*histp++ != 0) {
box->gmax = ig;
goto have_gmax;
}
}
}
have_gmax:
if (box->bmax > box->bmin) {
for (ib = box->bmin; ib <= box->bmax; ++ib)
for (ir = box->rmin; ir <= box->rmax; ++ir) {
histp = &histogram[ir][box->gmin][ib];
for (ig = box->gmin; ig <= box->gmax; ++ig) {
if (*histp != 0) {
box->bmin = ib;
goto have_bmin;
}
histp += B_LEN;
}
}
have_bmin:
if (box->bmax > box->bmin)
for (ib = box->bmax; ib >= box->bmin; --ib)
for (ir = box->rmin; ir <= box->rmax; ++ir) {
histp = &histogram[ir][box->gmin][ib];
ig = box->gmin;
for (; ig <= box->gmax; ++ig) {
if (*histp != 0) {
box->bmax = ib;
goto have_bmax;
}
histp += B_LEN;
}
}
}
have_bmax:
;
}
static C_cell *
create_colorcell(red, green, blue)
int red, green, blue;
{
register int ir, ig, ib, i;
register C_cell *ptr;
int mindist, next_n;
register int tmp, dist, n;
ir = red >> (COLOR_DEPTH-C_DEPTH);
ig = green >> (COLOR_DEPTH-C_DEPTH);
ib = blue >> (COLOR_DEPTH-C_DEPTH);
ptr = (C_cell *)malloc(sizeof (C_cell));
*(ColorCells + ir*C_LEN*C_LEN + ig*C_LEN + ib) = ptr;
ptr->num_ents = 0;
/*
* Step 1: find all colors inside this cell, while we're at
* it, find distance of centermost point to furthest corner
*/
mindist = 99999999;
for (i = 0; i < num_colors; ++i) {
if (rm[i]>>(COLOR_DEPTH-C_DEPTH) != ir ||
gm[i]>>(COLOR_DEPTH-C_DEPTH) != ig ||
bm[i]>>(COLOR_DEPTH-C_DEPTH) != ib)
continue;
ptr->entries[ptr->num_ents][0] = i;
ptr->entries[ptr->num_ents][1] = 0;
++ptr->num_ents;
tmp = rm[i] - red;
if (tmp < (MAX_COLOR/C_LEN/2))
tmp = MAX_COLOR/C_LEN-1 - tmp;
dist = tmp*tmp;
tmp = gm[i] - green;
if (tmp < (MAX_COLOR/C_LEN/2))
tmp = MAX_COLOR/C_LEN-1 - tmp;
dist += tmp*tmp;
tmp = bm[i] - blue;
if (tmp < (MAX_COLOR/C_LEN/2))
tmp = MAX_COLOR/C_LEN-1 - tmp;
dist += tmp*tmp;
if (dist < mindist)
mindist = dist;
}
/*
* Step 3: find all points within that distance to cell.
*/
for (i = 0; i < num_colors; ++i) {
if (rm[i] >> (COLOR_DEPTH-C_DEPTH) == ir &&
gm[i] >> (COLOR_DEPTH-C_DEPTH) == ig &&
bm[i] >> (COLOR_DEPTH-C_DEPTH) == ib)
continue;
dist = 0;
if ((tmp = red - rm[i]) > 0 ||
(tmp = rm[i] - (red + MAX_COLOR/C_LEN-1)) > 0 )
dist += tmp*tmp;
if ((tmp = green - gm[i]) > 0 ||
(tmp = gm[i] - (green + MAX_COLOR/C_LEN-1)) > 0 )
dist += tmp*tmp;
if ((tmp = blue - bm[i]) > 0 ||
(tmp = bm[i] - (blue + MAX_COLOR/C_LEN-1)) > 0 )
dist += tmp*tmp;
if (dist < mindist) {
ptr->entries[ptr->num_ents][0] = i;
ptr->entries[ptr->num_ents][1] = dist;
++ptr->num_ents;
}
}
/*
* Sort color cells by distance, use cheap exchange sort
*/
for (n = ptr->num_ents - 1; n > 0; n = next_n) {
next_n = 0;
for (i = 0; i < n; ++i)
if (ptr->entries[i][1] > ptr->entries[i+1][1]) {
tmp = ptr->entries[i][0];
ptr->entries[i][0] = ptr->entries[i+1][0];
ptr->entries[i+1][0] = tmp;
tmp = ptr->entries[i][1];
ptr->entries[i][1] = ptr->entries[i+1][1];
ptr->entries[i+1][1] = tmp;
next_n = i;
}
}
return (ptr);
}
static
map_colortable()
{
register int *histp = &histogram[0][0][0];
register C_cell *cell;
register int j, tmp, d2, dist;
int ir, ig, ib, i;
for (ir = 0; ir < B_LEN; ++ir)
for (ig = 0; ig < B_LEN; ++ig)
for (ib = 0; ib < B_LEN; ++ib, histp++) {
if (*histp == 0) {
*histp = -1;
continue;
}
cell = *(ColorCells +
(((ir>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) +
((ig>>(B_DEPTH-C_DEPTH)) << C_DEPTH) +
(ib>>(B_DEPTH-C_DEPTH))));
if (cell == NULL )
cell = create_colorcell(
ir << COLOR_SHIFT,
ig << COLOR_SHIFT,
ib << COLOR_SHIFT);
dist = 9999999;
for (i = 0; i < cell->num_ents &&
dist > cell->entries[i][1]; ++i) {
j = cell->entries[i][0];
d2 = rm[j] - (ir << COLOR_SHIFT);
d2 *= d2;
tmp = gm[j] - (ig << COLOR_SHIFT);
d2 += tmp*tmp;
tmp = bm[j] - (ib << COLOR_SHIFT);
d2 += tmp*tmp;
if (d2 < dist) {
dist = d2;
*histp = j;
}
}
}
}
/*
* straight quantization. Each pixel is mapped to the colors
* closest to it. Color values are rounded to the nearest color
* table entry.
*/
static
quant(in, out)
FILE *in, *out;
{
u_char *outline, *inline;
register u_char *outptr, *inptr;
register int i, j, red, green, blue;
i = 24 * width;
inline = (u_char *)malloc(howmany(i, 8));
outline = (u_char *)malloc(width);
for (i = 0; i < length; i++) {
if (fread(inline, 3*width, 1, in) <= 0)
break;
inptr = inline;
outptr = outline;
for (j = 0; j < width; j++) {
red = *inptr++ >> COLOR_SHIFT;
green = *inptr++ >> COLOR_SHIFT;
blue = *inptr++ >> COLOR_SHIFT;
*outptr++ = histogram[red][green][blue];
}
if (fwrite(outline, width, 1, out) <= 0)
break;
}
free(inline);
free(outline);
}
static
quant_fsdither(in, out)
FILE *in, *out;
{
u_char *outline, *inline, *inptr;
short *thisline, *nextline, *tmpptr;
register u_char *outptr;
register short *thisptr, *nextptr;
register int i, j, tmp;
int imax, jmax, lastline, lastpixel;
imax = length - 1;
jmax = width - 1;
i = 12 * width;
inline = (u_char *)malloc(howmany(i, 8));
thisline = (short *)malloc(width * 3 * sizeof (short));
nextline = (short *)malloc(width * 3 * sizeof (short));
outline = (unsigned char *) malloc(width);
/*
* Get first line
*/
if (fread(inline, 3*width, 1, in) <= 0)
return;
inptr = inline;
nextptr = nextline;
for (j = 0; j < width; ++j) {
*nextptr++ = *inptr++;
*nextptr++ = *inptr++;
*nextptr++ = *inptr++;
}
for (i = 0; i < length; ++i) {
tmpptr = thisline;
thisline = nextline;
nextline = tmpptr;
lastline = (i == imax);
if (fread(inline, 3*width, 1, in) <= 0)
break;
inptr = inline;
nextptr = nextline;
for (j = 0; j < width; ++j) {
*nextptr++ = *inptr++;
*nextptr++ = *inptr++;
*nextptr++ = *inptr++;
}
thisptr = thisline;
nextptr = nextline;
outptr = outline;
for (j = 0; j < width; ++j) {
int red, green, blue;
register int oval, r2, g2, b2;
lastpixel = (j == jmax);
b2 = *thisptr++;
g2 = *thisptr++;
r2 = *thisptr++;
if (r2 < 0)
r2 = 0;
else if (r2 >= MAX_COLOR)
r2 = MAX_COLOR-1;
if (g2 < 0)
g2 = 0;
else if (g2 >= MAX_COLOR)
g2 = MAX_COLOR-1;
if (b2 < 0)
b2 = 0;
else if (b2 >= MAX_COLOR)
b2 = MAX_COLOR-1;
red = r2;
green = g2;
blue = b2;
r2 >>= COLOR_SHIFT;
g2 >>= COLOR_SHIFT;
b2 >>= COLOR_SHIFT;
oval = histogram[r2][g2][b2];
if (oval == -1) {
int ci;
register int cj, tmp, d2, dist;
register C_cell *cell;
cell = *(ColorCells +
(((r2>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) +
((g2>>(B_DEPTH-C_DEPTH)) << C_DEPTH ) +
(b2>>(B_DEPTH-C_DEPTH))));
if (cell == NULL )
cell = create_colorcell(red,
green, blue);
dist = 9999999;
for (ci = 0; ci < cell->num_ents && dist > cell->entries[ci][1]; ++ci) {
cj = cell->entries[ci][0];
d2 = (rm[cj] >> COLOR_SHIFT) - r2;
d2 *= d2;
tmp = (gm[cj] >> COLOR_SHIFT) - g2;
d2 += tmp*tmp;
tmp = (bm[cj] >> COLOR_SHIFT) - b2;
d2 += tmp*tmp;
if (d2 < dist) {
dist = d2;
oval = cj;
}
}
histogram[r2][g2][b2] = oval;
}
*outptr++ = oval;
red -= rm[oval];
green -= gm[oval];
blue -= bm[oval];
if (!lastpixel) {
thisptr[0] += blue * 7 / 16;
thisptr[1] += green * 7 / 16;
thisptr[2] += red * 7 / 16;
}
if (!lastline) {
if (j != 0) {
nextptr[-3] += blue * 3 / 16;
nextptr[-2] += green * 3 / 16;
nextptr[-1] += red * 3 / 16;
}
nextptr[0] += blue * 5 / 16;
nextptr[1] += green * 5 / 16;
nextptr[2] += red * 5 / 16;
if (!lastpixel) {
nextptr[3] += blue / 16;
nextptr[4] += green / 16;
nextptr[5] += red / 16;
}
nextptr += 3;
}
}
if (fwrite(outline, width, 1, out) < 0)
break;
}
free(inline);
free(thisline);
free(nextline);
free(outline);
}